/*
* This file is a part of the open-eBackup project.
* This Source Code Form is subject to the terms of the Mozilla Public License, v. 2.0.
* If a copy of the MPL was not distributed with this file, You can obtain one at
* http://mozilla.org/MPL/2.0/.
*
* Copyright (c) [2024] Huawei Technologies Co.,Ltd.
*
* THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND,
* EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT,
* MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE.
*/
#include "ScClient.h"
#include "protect_engines/hcs/utils/HCSTokenMgr.h"
#include "log/Log.h"

namespace {
const std::string MODULE_NAME = "ScClient";
using Defer = std::shared_ptr<void>;
}

HCS_PLUGIN_NAMESPACE_BEGIN

bool ScClient::CheckParams(ModelBase &model)
{
    if (!model.UserInfoIsSet()) {
        ERRLOG("The param user not be set.");
        return false;
    }
    if (!model.DomainIsSet()) {
        ERRLOG("The param domain not be set.");
        return false;
    }
    if (!model.EndPointIsSet()) {
        ERRLOG("The param endpoint not be set.");
        return false;
    }
    if (!model.ScopeValueIsSet()) {
        ERRLOG("The param scope not be set.");
        return false;
    }
    return true;
}

// Reacquire token when token expired
bool ScClient::UpdateToken(ModelBase &request, std::string &tokenStr)
{
    if (!HCSTokenMgr::GetInstance().ReacquireToken(request, tokenStr)) {
        ERRLOG("Get token failed.");
        return false;
    }
    return true;
}

std::shared_ptr<QueryVdcListResponse> ScClient::QueryVdcList(QueryVdcListRequest &request)
{
    if (!CheckParams(request)) {
        ERRLOG("Failed to check param.");
        return nullptr;
    }

    RequestInfo requestInfo;
    requestInfo.m_method = "GET";
    requestInfo.m_resourcePath = "https://sc.{endpoint}/rest/vdc/v3.0/vdcs";
    std::string tokenStr;
    std::string endpoint;
    HCSTokenMgr::GetInstance().DeleteToken(request);
    if (!HCSTokenMgr::GetInstance().GetToken(request, tokenStr, endpoint)) {
        ERRLOG("Failed to get token.");
        return nullptr;
    }
    requestInfo.m_pathParams["endpoint"] = request.GetEndpoint();   // sc从外部获取endpoint
    requestInfo.m_headerParams["Content-Type"] = "application/json";
    requestInfo.m_headerParams["X-Auth-Token"] = tokenStr;
    requestInfo.m_body = "";
    requestInfo.m_auth = request.GetUserInfo();

    if (request.StartIsSet()) {
        requestInfo.m_queryParams["start"] = std::to_string(request.GetStart());
    }
    if (request.LimitIsSet()) {
        requestInfo.m_queryParams["limit"] = std::to_string(request.GetLimit());
    }
    if (request.UpperVdcIdIsSet()) {
        requestInfo.m_queryParams["upper_vdc_id"] = request.GetUpperVdcId();
    }
    if (request.LevelIsSet()) {
        requestInfo.m_queryParams["level"] = std::to_string(request.GetLevel());
    }
    if (request.IsDomainIsSet()) {
        requestInfo.m_queryParams["is_domain"] = request.GetIsDomain();
    }
    if (request.DomainIdIsSet()) {
        requestInfo.m_queryParams["domain_id"] = request.GetDomainId();
    }

    std::shared_ptr<QueryVdcListResponse> response = std::make_shared<QueryVdcListResponse>();
    if (CallApi(requestInfo, response, request) != SUCCESS) {
        ERRLOG("Failed to send request to hcs.");
        return response;
    }
    if (!response->Serial()) {
        ERRLOG("Failed to serial data.");
        return response;
    }
    return response;
}

std::shared_ptr<QueryResourceListResponse> ScClient::QueryResourceList(QueryResourceListRequest &request)
{
    if (!CheckParams(request) || (!request.VdcManagerIdIsSet())) {
        ERRLOG("Failed to check param.");
        return nullptr;
    }

    RequestInfo requestInfo;
    requestInfo.m_method = "GET";
    requestInfo.m_resourcePath = "https://sc.{endpoint}/rest/vdc/v3.1/vdcs/{userId}/projects";
    std::string tokenStr;
    std::string endpoint;
    if (!HCSTokenMgr::GetInstance().GetToken(request, tokenStr, endpoint)) {
        ERRLOG("Failed to get token.");
        return nullptr;
    }
    requestInfo.m_pathParams["endpoint"] = request.GetEndpoint();   // sc从外部获取endpoint
    requestInfo.m_pathParams["userId"] = request.GetVdcManagerId();
    requestInfo.m_queryParams = {};
    requestInfo.m_headerParams["Content-Type"] = "application/json";
    requestInfo.m_headerParams["X-Auth-Token"] = tokenStr;
    if (request.GetStartIsSet()) {
        requestInfo.m_queryParams["start"] = std::to_string(request.GetStart());
    }
    if (request.GetLimitIsSet()) {
        requestInfo.m_queryParams["limit"] = std::to_string(request.GetLimit());
    }
    requestInfo.m_body = "";
    requestInfo.m_auth = request.GetUserInfo();

    if (request.GetQueryAllProjectIsSet()) {
        requestInfo.m_queryParams["inherit"] = request.GetQueryAllProjectStr();
    }

    std::shared_ptr<QueryResourceListResponse> response = std::make_shared<QueryResourceListResponse>();
    if (CallApi(requestInfo, response, request) != SUCCESS) {
        ERRLOG("Failed to send request to hcs.");
        return response;
    }
    if (!response->Serial()) {
        ERRLOG("Failed to serial data.");
        return nullptr;
    }
    return response;
}

std::shared_ptr<QueryProjectDetailResponse> ScClient::QueryProjectDetail(QueryProjectDetailRequest &request)
{
    if (!CheckParams(request) || (!request.ProjectIdIsSet())) {
        ERRLOG("Failed to check param.");
        return nullptr;
    }

    RequestInfo requestInfo;
    requestInfo.m_method = "GET";
    requestInfo.m_resourcePath = "https://sc.{endpoint}/rest/vdc/v3.1/projects/{projectId}";
    std::string endpoint;
    std::string tokenStr;
    if (!HCSTokenMgr::GetInstance().GetToken(request, tokenStr, endpoint)) {
        ERRLOG("Failed to get token.");
        return nullptr;
    }
    requestInfo.m_pathParams["endpoint"] = request.GetEndpoint();   // sc从外部获取endpoint
    requestInfo.m_pathParams["projectId"] = request.GetProjectId();
    requestInfo.m_queryParams = {};
    requestInfo.m_headerParams["Content-Type"] = "application/json";
    requestInfo.m_headerParams["X-Auth-Token"] = tokenStr;
    requestInfo.m_body = "";
    requestInfo.m_auth = request.GetUserInfo();

    std::shared_ptr<QueryProjectDetailResponse> response = std::make_shared<QueryProjectDetailResponse>();
    if (CallApi(requestInfo, response, request) != SUCCESS) {
        ERRLOG("Failed to send request to hcs.");
        return response;
    }
    if (!response->Serial()) {
        ERRLOG("Failed to serial data.");
        return response;
    }
    return response;
}

std::shared_ptr<GetVdcUserDetailResponse> ScClient::GetVDCUserDetailInfo(GetVdcUserDetailRequest &request)
{
    if (!CheckParams(request)) {
        ERRLOG("Failed to check get account detail param.");
        return nullptr;
    }
    std::string endpoint;
    std::string tokenStr;
    Defer _(nullptr, [&](...) { Module::CleanMemoryPwd(tokenStr); });
    if (!HCSTokenMgr::GetInstance().GetToken(request, tokenStr, endpoint)) {
        ERRLOG("Get token failed.");
        return nullptr;
    }
    RequestInfo requestInfo;
    requestInfo.m_method = "GET";
    requestInfo.m_resourcePath = "https://sc.{endpoint}/rest/vdc/v3.0/users/{userId}";
    requestInfo.m_pathParams["endpoint"] = request.GetEndpoint();
    requestInfo.m_pathParams["userId"] = request.GetUserName();
    requestInfo.m_queryParams["type"] = "name";
    requestInfo.m_headerParams["X-Auth-Token"] = tokenStr;
    requestInfo.m_auth = request.GetUserInfo();
    std::shared_ptr<GetVdcUserDetailResponse> response = std::make_shared<GetVdcUserDetailResponse>();
    if (CallApi(requestInfo, response, request) != SUCCESS) {
        ERRLOG("Failed to send request to get account detail.");
        return response;
    }
    return response;
}

HCS_PLUGIN_NAMESPACE_END